package com.lida.study.sudo;

import com.lida.study.common.utils.sudo.SudoUtils;
import lombok.Data;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;

/**
 * 数独实体
 * @author lD
 * @date 2019/7/314:01
 */
@Data
public class Sudo implements Serializable {

    /**
     * 所有数据都在这里
     * 列+可能数
     */
    private Map<Integer, Map<Integer, Set<Integer>>> data;

    /**
     * 假定值，当普通尝试不能解决时，给出假定值继续尝试，假定数独放在这里
     */
    private List<Sudo> children;

    private Sudo() {
        reset();
    }

    public Sudo(int size) {
        SudoUtils.setSize(size);
        reset();
    }

    private Sudo(Map<Integer, Map<Integer, Set<Integer>>> data) {
        this.data = data;
    }

    /**
     * 指定坐标赋值
     * @param x 列
     * @param y 行
     * @param value 数据
     */
    public void set(int x, int y, Set<Integer> value) {
        this.data.get(x).put(y, new HashSet<>(value));
    }

    /**
     * 指定坐标赋值
     * @param x 列
     * @param y 行
     * @param value 数据
     */
    public void set(int x, int y, int value) {
        Set<Integer> data1 = new HashSet<>();
        data1.add(value);
        this.data.get(x).put(y, data1);
    }

    /**
     * 指定坐标添加可能值
     * @param x 列
     * @param y 行
     * @param value 数据
     */
    public void add(int x, int y, Set<Integer> value) {
        this.data.get(x).get(y).addAll(value);
    }

    /**
     * 指定坐标添加可能值
     * @param x 列
     * @param y 行
     * @param value 数据
     */
    public void add(int x, int y, Integer value) {
        this.data.get(x).get(y).add(value);
    }

    /**
     * 获取指定坐标的值
     * @param x 列
     * @param y 行
     * @return
     */
    public Set<Integer> get(int x, int y) {
        if (CollectionUtils.isEmpty(this.data)) {
            new ArrayList<Integer>();
        }
        return this.data.get(x).get(y);
    }

    /**
     * 初始化数独
     */
    public void reset() {
        this.data = new HashMap<>(16);
        for (int i = 0; i < SudoUtils.getSize(); i++) {
            Map<Integer, Set<Integer>> map = new HashMap<>(16);
            for (int j = 0; j < SudoUtils.getSize(); j++) {
                map.put(j, new HashSet<>());
            }
            this.data.put(i, map);
        }
    }

    /**
     * 获取总数
     * @return
     */
    public int getCount() {
        int count = 0;
        for (int i = 0; i < SudoUtils.getSize(); i++) {
            for (int j = 0; j < SudoUtils.getSize(); j++) {
                count += get(i, j).size();
            }
        }
        return count;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < SudoUtils.getSize(); i++) {
            for (int j = 0; j < SudoUtils.getSize(); j++) {
                Set<Integer> value = this.data.get(j).get(i);
                for (Integer integer : value) {
                    sb.append(integer);
                }
                int k = SudoUtils.getSize() - value.size();
                do {
                    sb.append(" ");
                    k--;
                } while (k > 0);
            }
            sb.append("\n");
        }
        return sb.toString();
    }

    @Override
    public Sudo clone() {
        if (CollectionUtils.isEmpty(data)) {
            return new Sudo();
        }
        return new Sudo(cloneData());
    }

    private Map<Integer, Map<Integer, Set<Integer>>> cloneData() {
        Map<Integer, Map<Integer, Set<Integer>>> resultNew = new HashMap<>(16);
        for (Map.Entry<Integer, Map<Integer, Set<Integer>>> entry : data.entrySet()) {
            Map<Integer, Set<Integer>> map = new HashMap<>(16);
            for (Map.Entry<Integer, Set<Integer>> entry1 : entry.getValue().entrySet()) {
                map.put(entry1.getKey(), new HashSet<>(entry1.getValue()));
            }
            resultNew.put(entry.getKey(), map);
        }
        return resultNew;
    }
}
